import hxbase.events.Event;
//import hxbase.js.Dom;

class MyEventGroup extends EventGroup
{
	var doSomething : Event<Int -> Int -> Int -> Void>;
	var doAnother : Event<Void->Void>;
}

class MyDispatchingClass implements EventDispatchers<MyEventGroup>
{
	public var events : MyEventGroup;
	var c : MyClass;
	public function new(c)
	{
		this.c = c;
		//events = new MyEventGroup(this);
		events = new MyEventGroup();
	}
	
	public function doIt()
	{
		c.str = '';
		events.doSomething.call(1,2,3);
		c.check();
	}
}


typedef MyClassHandlers = {
	var a : Binding;
	var b : Binding;
	var c : Binding;
	var d : Binding;
}

class MyClass implements EventHandlers<MyClassHandlers>
{
	public var handlers : MyClassHandlers;
	
	public var str : String;
	
	var activeA : Bool;
	var activeB : Bool;
	var activeC : Bool;
	var activeD : Bool;
	
	public function check()
	{
		var s = '';
		if(activeD) s += 'D';
		if(activeC) s += 'C';
		if(activeB) s += 'B';
		if(activeA) s += 'A';
		
		if(s != str) trace( str+' != '+s );
	}
	
	public function new()
	{
		var x = new MyDispatchingClass(this);
		
		Event.global(MyEventGroup);
		
		activeA = true;
		activeB = true;
		activeC = true;
		activeD = true;
		
		//handlers = {
		var a = x.events.doSomething.bind(this, doSomething1);
		var b = x.events.doSomething.bind(this, doSomething2);
		var c = x.events.doSomething.bind(this, doSomething3);
		var d = x.events.doSomething.bind(this, doSomething4);
		//};
		
		//trace(untyped d == a.d.lastHandler);
		
		//Event.global(MyEventGroup).doSomething.bind(null,null).
		
		//var action = [0,2,4,6 , 1,5,3];
		for(i in 0 ... 10000) //action.length)
		{
			switch(Std.random(8))
		//	switch(action[i])
			{
				case 0:
					//trace('Disable A');
					activeA = false;
					a.disable();
				case 1:
					//trace('Enable A');
					activeA = true;
					a.enable();
				case 2:
					//trace('Disable B');
					activeB = false;
					b.disable();
				case 3:
					//trace('Enable B');
					activeB = true;
					b.enable();
				case 4:
					//trace('Disable C');
					activeC = false;
					c.disable();
				case 5:
					//trace('Enable C');
					activeC = true;
					c.enable();
				case 6:
					if(d == null) continue;
					//trace('Disable D');
					activeD = false;
					d.disable();
				case 7:
					if(d == null) continue;
					//trace('Enable D');
					activeD = true;
					d.enable();
				case 8:
		//			Bubble.unlink(d);
		//			d = null;
					//x.events.doSomething.unbind();
			}
		}
		if(activeA) trace('A Enabled');
		if(activeB) trace('B Enabled');
		if(activeC) trace('C Enabled');
		if(activeD) trace('D Enabled');
		
		x.doIt();
		trace(' --------------------------- ');
		trace(' ----> Result: '+str);
		trace(' --------------------------- ');
		
		
		trace('remove all');
		activeA = activeB = activeC = activeD = false;
		x.events.doSomething.unbind(this);
		
		x.doIt();
		trace(' --------------------------- ');
		trace(' ----> Result: '+str);
		trace(' --------------------------- ');
		trace('done, Result should be empty.');
		/*
		#if neko
		var b = neko.Sys.time();
		#else true
		var b = Date.
		#end
		for(i in 0 ... 1000) {
			x.events.doSomething.bind(this, doBench);
		}
		trace( neko.Sys.time() - b );
		*/
	}
	
	function doSomething1(a:Int,b:Int,c:Int)
	{
		str += 'A';
	}
	function doSomething2(a:Int,b:Int,c:Int)
	{
		str += 'B';
	}
	function doSomething3(a:Int,b:Int,c:Int)
	{
		str += 'C';
	}
	function doSomething4(a:Int,b:Int,c:Int)
	{
		str += 'D';
	}
	function doSomething5(a:Int,b:Int,c:Int)
	{
		trace('|');
	}
	
	function doBench(a:Int, b:Int, c:Int)
	{
		a+b+c;
	}
}

class QuickTest
{ 
	public static function main()
	{
		var x = new MyClass();
		
		
	}
}